package SpLib.Net
{
	import SpLib.Com.SpLibEvent;
	import SpLib.Tools.Tr;
	import SpLib.std.queue;
	
	import flash.display.Loader;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.TimerEvent;
	import flash.net.URLRequest;
	import flash.system.ApplicationDomain;
	import flash.system.LoaderContext;
	import flash.utils.Timer;

	public class NetLoaderQue extends EventDispatcher
	{
		public static var EVE_STARTDOWN:String = "SpLibNetLoaderQueStartDown";
		public static var EVE_PROGRESS:String = "SpLibNetLoaderQueProgress";
		public static var EVE_DOWNERR:String = "SpLibNetLoaderQueDownErr";
		public static var EVE_DOWNOK:String = "SpLibNetLoaderQueDownOk";
		public static var EVE_COMPLETE:String = "SpLibNetLoaderQueComplete";
		
		public static const DEF_MAX_RET_TIMES:int = 3;
		public static const DEF_MAX_TIMEOUT:int = 3000;
		
		private var m_DownList:SpLib.std.queue = new SpLib.std.queue();
		private var m_sCurDown:String;
		private var m_sDownUrl:String = "";
		private var m_bDownloading:Boolean = false;
		
		private var m_nRegetTimes:int = 0;
		private var m_nMaxRetryTimes:int;
		
		private var m_Timer:Timer = null;
		private var m_nOutTime:int = DEF_MAX_TIMEOUT;
		private var m_Loader:flash.display.Loader;
		private var m_LoaderContext:flash.system.LoaderContext;
		
		public function NetLoaderQue(filelist:Array=null,retry:int = DEF_MAX_RET_TIMES,timeout:int = -1)
		{
			super();
			
			m_LoaderContext = new flash.system.LoaderContext();
			m_LoaderContext.applicationDomain = ApplicationDomain.currentDomain;
			
			m_nOutTime = timeout;
			m_nMaxRetryTimes = retry;
			AddDown(filelist);
		}
		
		public function AddDown(filelist:Array = null):void
		{
			if(filelist==null) return;
			
			var i:int;
			for(i=0;i<filelist.length;i++)
			{
				m_DownList.push( filelist[i] as String);
			}
		}
		
		public function Start():void
		{
			if(m_bDownloading) return;

			if(!m_DownList.empty())
			{
				DonwFile(m_DownList.pop() as String);
			}
			else
			{
				m_bDownloading = false;
				this.dispatchEvent(new SpLibEvent(EVE_COMPLETE,"OnDownOk"));
			}
		}
			
		private function DonwFile(file:String):void
		{
			m_bDownloading = true;
			
			this.dispatchEvent(new SpLibEvent(EVE_STARTDOWN,"OnStartDown",[m_sCurDown]));
			
			m_nRegetTimes = 0;
			m_sCurDown = file;
			m_sDownUrl = SpLib.Net.URLResMgr.MakeUrl(m_sCurDown);
			
			if(m_nOutTime>0)
			{
				m_Timer = new Timer(m_nOutTime);
			}
			
			m_Loader = new flash.display.Loader();
			if(m_Timer!=null)
			{
				m_Timer.addEventListener(TimerEvent.TIMER,OnOutTime);
			}

			m_Loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR,OnIOError);
        	m_Loader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR,OnSecurityError);
        	m_Loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS,OnProgress);
        	m_Loader.contentLoaderInfo.addEventListener(Event.COMPLETE,OnDownOk);
        	
			Try();
		}
		
		private function Try():void
		{
			m_Loader.load(new URLRequest(m_sDownUrl),m_LoaderContext);

			if(m_Timer!=null)
			{
				m_Timer.reset();
				m_Timer.start();
			}
		}
		
		private function Retry():void
		{
			if(m_nRegetTimes++<m_nMaxRetryTimes)
			{
				Try();
			}
			else
			{
				if(m_Timer!=null)
				{
					m_Timer.removeEventListener(TimerEvent.TIMER,OnOutTime);
				}
				
				m_Loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR,OnIOError);
				m_Loader.contentLoaderInfo.removeEventListener(IOErrorEvent.NETWORK_ERROR,OnIOError);
	        	m_Loader.contentLoaderInfo.removeEventListener(SecurityErrorEvent.SECURITY_ERROR,OnSecurityError);
	        	m_Loader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS,OnProgress);
				m_Loader.contentLoaderInfo.removeEventListener(Event.COMPLETE,OnDownOk);
				m_Loader = null;
				
				this.dispatchEvent(new SpLibEvent(EVE_DOWNERR,"OnDownErr",[m_sCurDown]));
			}
		}
		
		private function OnOutTime(evt:TimerEvent):void
		{		
			SpLib.Tools.Tr.Error("下载【"+m_sCurDown+"】超时，重试...");
			Retry();
		}
		
		private function OnIOError(evt:IOErrorEvent):void
		{
			SpLib.Tools.Tr.Error("下载【"+m_sCurDown+"】IO错误，"+evt.text+"，重试...");
			Retry();
		}
		
		private function OnSecurityError(evt:SecurityErrorEvent):void
		{
			Retry();
		}
		
		private function OnProgress(evt:ProgressEvent):void
		{
			this.dispatchEvent(new SpLibEvent(EVE_PROGRESS,"OnDownProgress",[m_sCurDown,evt.bytesLoaded,evt.bytesTotal]));
		}
		
		private function OnDownOk(evt:Event):void
		{
			SpLib.Tools.Tr.SysNote("下载【"+m_sCurDown+"】成功.");
			this.dispatchEvent(new SpLibEvent(EVE_DOWNOK,"OnDownOk",[m_sCurDown,m_Loader.contentLoaderInfo]));
			
			if(!m_DownList.empty())
			{
				DonwFile(m_DownList.pop() as String);
			}
			else
			{
				m_bDownloading = false;
				this.dispatchEvent(new SpLibEvent(EVE_COMPLETE,"OnDownComplete"));
			}
		}
	}
}